home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / P_PSPR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  57.9 KB  |  2,457 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** p_pspr.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: p_pspr.c,v $
  7. //** $Revision: 1.105 $
  8. //** $Date: 96/01/06 03:23:35 $
  9. //** $Author: bgokey $
  10. //**
  11. //**************************************************************************
  12.  
  13. // HEADER FILES ------------------------------------------------------------
  14.  
  15. #include "h2def.h"
  16. #include "p_local.h"
  17. #include "soundst.h"
  18.  
  19. // MACROS ------------------------------------------------------------------
  20.  
  21. #define LOWERSPEED FRACUNIT*6
  22. #define RAISESPEED FRACUNIT*6
  23. #define WEAPONBOTTOM 128*FRACUNIT
  24. #define WEAPONTOP 32*FRACUNIT
  25.  
  26. // TYPES -------------------------------------------------------------------
  27.  
  28. // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
  29.  
  30. extern void P_ExplodeMissile(mobj_t *mo);
  31. extern void A_UnHideThing(mobj_t *actor);
  32.  
  33. // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
  34.  
  35. // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
  36.  
  37. // EXTERNAL DATA DECLARATIONS ----------------------------------------------
  38.  
  39. extern fixed_t FloatBobOffsets[64];
  40.  
  41. // PUBLIC DATA DEFINITIONS -------------------------------------------------
  42.  
  43. fixed_t bulletslope;
  44.  
  45. weaponinfo_t WeaponInfo[NUMWEAPONS][NUMCLASSES] =
  46. {
  47.     { // First Weapons
  48.         { // Fighter First Weapon - Punch
  49.             MANA_NONE,            // mana
  50.             S_PUNCHUP,            // upstate
  51.             S_PUNCHDOWN,        // downstate
  52.             S_PUNCHREADY,        // readystate
  53.             S_PUNCHATK1_1,        // atkstate
  54.             S_PUNCHATK1_1,        // holdatkstate
  55.             S_NULL                // flashstate
  56.         },
  57.         { // Cleric First Weapon - Mace
  58.             MANA_NONE,            // mana
  59.             S_CMACEUP,            // upstate
  60.             S_CMACEDOWN,        // downstate
  61.             S_CMACEREADY,        // readystate
  62.             S_CMACEATK_1,        // atkstate
  63.             S_CMACEATK_1,        // holdatkstate
  64.             S_NULL                // flashstate
  65.         },
  66.         { // Mage First Weapon - Wand
  67.             MANA_NONE,
  68.             S_MWANDUP,
  69.             S_MWANDDOWN,
  70.             S_MWANDREADY,
  71.             S_MWANDATK_1,
  72.             S_MWANDATK_1,
  73.             S_NULL
  74.         },
  75.         { // Pig - Snout
  76.             MANA_NONE,            // mana
  77.             S_SNOUTUP,            // upstate
  78.             S_SNOUTDOWN,        // downstate
  79.             S_SNOUTREADY,        // readystate
  80.             S_SNOUTATK1,        // atkstate
  81.             S_SNOUTATK1,        // holdatkstate
  82.             S_NULL                // flashstate
  83.         }
  84.     },
  85.     { // Second Weapons
  86.         { // Fighter - Axe
  87.             MANA_NONE,            // mana
  88.             S_FAXEUP,            // upstate
  89.             S_FAXEDOWN,            // downstate
  90.             S_FAXEREADY,        // readystate
  91.             S_FAXEATK_1,        // atkstate
  92.             S_FAXEATK_1,        // holdatkstate
  93.             S_NULL                // flashstate
  94.         },
  95.         { // Cleric - Serpent Staff
  96.             MANA_1,            // mana
  97.             S_CSTAFFUP,        // upstate
  98.             S_CSTAFFDOWN,    // downstate
  99.             S_CSTAFFREADY,    // readystate
  100.             S_CSTAFFATK_1,    // atkstate
  101.             S_CSTAFFATK_1,    // holdatkstate
  102.             S_NULL            // flashstate
  103.         },
  104.         { // Mage - Cone of shards
  105.             MANA_1,            // mana
  106.             S_CONEUP,        // upstate
  107.             S_CONEDOWN,        // downstate
  108.             S_CONEREADY,    // readystate
  109.             S_CONEATK1_1,    // atkstate
  110.             S_CONEATK1_3,    // holdatkstate
  111.             S_NULL            // flashstate
  112.         },
  113.         { // Pig - Snout
  114.             MANA_NONE,            // mana
  115.             S_SNOUTUP,            // upstate
  116.             S_SNOUTDOWN,        // downstate
  117.             S_SNOUTREADY,        // readystate
  118.             S_SNOUTATK1,        // atkstate
  119.             S_SNOUTATK1,        // holdatkstate
  120.             S_NULL                // flashstate
  121.         }
  122.     },
  123.     { // Third Weapons
  124.         { // Fighter - Hammer
  125.             MANA_NONE,            // mana
  126.             S_FHAMMERUP,        // upstate
  127.             S_FHAMMERDOWN,        // downstate
  128.             S_FHAMMERREADY,        // readystate
  129.             S_FHAMMERATK_1,        // atkstate
  130.             S_FHAMMERATK_1,        // holdatkstate
  131.             S_NULL                // flashstate
  132.         },
  133.         { // Cleric - Flame Strike
  134.             MANA_2,                // mana
  135.             S_CFLAMEUP,            // upstate
  136.             S_CFLAMEDOWN,        // downstate
  137.             S_CFLAMEREADY1,        // readystate
  138.             S_CFLAMEATK_1,        // atkstate
  139.             S_CFLAMEATK_1,        // holdatkstate
  140.             S_NULL                // flashstate
  141.         },
  142.         { // Mage - Lightning
  143.             MANA_2,        // mana
  144.             S_MLIGHTNINGUP,        // upstate
  145.             S_MLIGHTNINGDOWN,    // downstate
  146.             S_MLIGHTNINGREADY,    // readystate
  147.             S_MLIGHTNINGATK_1,    // atkstate
  148.             S_MLIGHTNINGATK_1,    // holdatkstate
  149.             S_NULL                // flashstate
  150.         },
  151.         { // Pig - Snout
  152.             MANA_NONE,            // mana
  153.             S_SNOUTUP,            // upstate
  154.             S_SNOUTDOWN,        // downstate
  155.             S_SNOUTREADY,        // readystate
  156.             S_SNOUTATK1,        // atkstate
  157.             S_SNOUTATK1,        // holdatkstate
  158.             S_NULL                // flashstate
  159.         }
  160.     },
  161.     { // Fourth Weapons
  162.         { // Fighter - Rune Sword
  163.             MANA_BOTH,            // mana
  164.             S_FSWORDUP,            // upstate
  165.             S_FSWORDDOWN,        // downstate
  166.             S_FSWORDREADY,        // readystate
  167.             S_FSWORDATK_1,        // atkstate
  168.             S_FSWORDATK_1,        // holdatkstate
  169.             S_NULL                // flashstate
  170.         },
  171.         { // Cleric - Holy Symbol
  172.             MANA_BOTH,            // mana
  173.             S_CHOLYUP,        // upstate
  174.             S_CHOLYDOWN,        // downstate
  175.             S_CHOLYREADY,        // readystate
  176.             S_CHOLYATK_1,        // atkstate
  177.             S_CHOLYATK_1,        // holdatkstate
  178.             S_NULL                // flashstate
  179.         },
  180.         { // Mage - Staff
  181.             MANA_BOTH,        // mana
  182.             S_MSTAFFUP,        // upstate
  183.             S_MSTAFFDOWN,        // downstate
  184.             S_MSTAFFREADY,        // readystate
  185.             S_MSTAFFATK_1,    // atkstate
  186.             S_MSTAFFATK_1,    // holdatkstate
  187.             S_NULL                // flashstate
  188.         },
  189.         { // Pig - Snout
  190.             MANA_NONE,            // mana
  191.             S_SNOUTUP,            // upstate
  192.             S_SNOUTDOWN,        // downstate
  193.             S_SNOUTREADY,        // readystate
  194.             S_SNOUTATK1,        // atkstate
  195.             S_SNOUTATK1,        // holdatkstate
  196.             S_NULL                // flashstate
  197.         }
  198.     }
  199. };
  200.  
  201. // PRIVATE DATA DEFINITIONS ------------------------------------------------
  202.  
  203. static int WeaponManaUse[NUMCLASSES][NUMWEAPONS] = 
  204. {
  205.     { 0, 2, 3, 14 },
  206.     { 0, 1, 4, 18 },
  207.     { 0, 3, 5, 15 },
  208.     { 0, 0, 0, 0 }
  209. };
  210.  
  211. // CODE --------------------------------------------------------------------
  212.  
  213. //---------------------------------------------------------------------------
  214. //
  215. // PROC P_SetPsprite
  216. //
  217. //---------------------------------------------------------------------------
  218.  
  219. void P_SetPsprite(player_t *player, int position, statenum_t stnum)
  220. {
  221.     pspdef_t *psp;
  222.     state_t *state;
  223.  
  224.     psp = &player->psprites[position];
  225.     do
  226.     {
  227.         if(!stnum)
  228.         { // Object removed itself.
  229.             psp->state = NULL;
  230.             break;
  231.         }
  232.         state = &states[stnum];
  233.         psp->state = state;
  234.         psp->tics = state->tics; // could be 0
  235.         if(state->misc1)
  236.         { // Set coordinates.
  237.             psp->sx = state->misc1<<FRACBITS;
  238.         }
  239.         if(state->misc2)
  240.         {
  241.             psp->sy = state->misc2<<FRACBITS;
  242.         }
  243.         if(state->action)
  244.         { // Call action routine.
  245.             state->action(player, psp);
  246.             if(!psp->state)
  247.             {
  248.                 break;
  249.             }
  250.         }
  251.         stnum = psp->state->nextstate;
  252.     } while(!psp->tics); // An initial state of 0 could cycle through.
  253. }
  254.  
  255. //---------------------------------------------------------------------------
  256. //
  257. // PROC P_SetPspriteNF
  258. //
  259. // Identical to P_SetPsprite, without calling the action function
  260. //---------------------------------------------------------------------------
  261.  
  262. void P_SetPspriteNF(player_t *player, int position, statenum_t stnum)
  263. {
  264.     pspdef_t *psp;
  265.     state_t *state;
  266.  
  267.     psp = &player->psprites[position];
  268.     do
  269.     {
  270.         if(!stnum)
  271.         { // Object removed itself.
  272.             psp->state = NULL;
  273.             break;
  274.         }
  275.         state = &states[stnum];
  276.         psp->state = state;
  277.         psp->tics = state->tics; // could be 0
  278.         if(state->misc1)
  279.         { // Set coordinates.
  280.             psp->sx = state->misc1<<FRACBITS;
  281.         }
  282.         if(state->misc2)
  283.         {
  284.             psp->sy = state->misc2<<FRACBITS;
  285.         }
  286.         stnum = psp->state->nextstate;
  287.     } while(!psp->tics); // An initial state of 0 could cycle through.
  288. }
  289.  
  290. /*
  291. =================
  292. =
  293. = P_CalcSwing
  294. =
  295. =================
  296. */
  297.  
  298. /*
  299. fixed_t    swingx, swingy;
  300. void P_CalcSwing (player_t *player)
  301. {
  302.     fixed_t    swing;
  303.     int        angle;
  304.  
  305. // OPTIMIZE: tablify this
  306.  
  307.     swing = player->bob;
  308.  
  309.     angle = (FINEANGLES/70*leveltime)&FINEMASK;
  310.     swingx = FixedMul ( swing, finesine[angle]);
  311.  
  312.     angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
  313.     swingy = -FixedMul ( swingx, finesine[angle]);
  314. }
  315. */
  316.  
  317. //---------------------------------------------------------------------------
  318. //
  319. // PROC P_ActivateMorphWeapon
  320. //
  321. //---------------------------------------------------------------------------
  322.  
  323. void P_ActivateMorphWeapon(player_t *player)
  324. {
  325.     player->pendingweapon = WP_NOCHANGE;
  326.     player->psprites[ps_weapon].sy = WEAPONTOP;
  327.     player->readyweapon = WP_FIRST;    // Snout is the first weapon
  328.     P_SetPsprite(player, ps_weapon, S_SNOUTREADY);
  329. }
  330.  
  331.  
  332. //---------------------------------------------------------------------------
  333. //
  334. // PROC P_PostMorphWeapon
  335. //
  336. //---------------------------------------------------------------------------
  337.  
  338. void P_PostMorphWeapon(player_t *player, weapontype_t weapon)
  339. {
  340.     player->pendingweapon = WP_NOCHANGE;
  341.     player->readyweapon = weapon;
  342.     player->psprites[ps_weapon].sy = WEAPONBOTTOM;
  343.     P_SetPsprite(player, ps_weapon, WeaponInfo[weapon][player->class].upstate);
  344. }
  345.  
  346. //---------------------------------------------------------------------------
  347. //
  348. // PROC P_BringUpWeapon
  349. //
  350. // Starts bringing the pending weapon up from the bottom of the screen.
  351. //
  352. //---------------------------------------------------------------------------
  353.  
  354. void P_BringUpWeapon(player_t *player)
  355. {
  356.     statenum_t new;
  357.  
  358.     if(player->pendingweapon == WP_NOCHANGE)
  359.     {
  360.         player->pendingweapon = player->readyweapon;
  361.     }
  362.     if(player->class == PCLASS_FIGHTER && player->pendingweapon == WP_SECOND
  363.     && player->mana[MANA_1])
  364.     {
  365.         new = S_FAXEUP_G;
  366.     }
  367.     else
  368.     {
  369.         new = WeaponInfo[player->pendingweapon][player->class].upstate;
  370.     }
  371.     player->pendingweapon = WP_NOCHANGE;
  372.     player->psprites[ps_weapon].sy = WEAPONBOTTOM;
  373.     P_SetPsprite(player, ps_weapon, new);
  374. }
  375.  
  376. //---------------------------------------------------------------------------
  377. //
  378. // FUNC P_CheckMana
  379. //
  380. // Returns true if there is enough mana to shoot.  If not, selects the
  381. // next weapon to use.
  382. //
  383. //---------------------------------------------------------------------------
  384.  
  385. boolean P_CheckMana(player_t *player)
  386. {
  387.     manatype_t mana;
  388.     int count;
  389.  
  390.     mana = WeaponInfo[player->readyweapon][player->class].mana;
  391.     count = WeaponManaUse[player->class][player->readyweapon];
  392.     if(mana == MANA_BOTH)
  393.     {
  394.         if(player->mana[MANA_1] >= count && player->mana[MANA_2] >= count)
  395.         {
  396.             return true;
  397.         }
  398.     }
  399.     else if(mana == MANA_NONE || player->mana[mana] >= count)
  400.     {
  401.         return(true);
  402.     }
  403.     // out of mana, pick a weapon to change to
  404.     do
  405.     {
  406.         if(player->weaponowned[WP_THIRD]
  407.             && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_THIRD])
  408.         {
  409.             player->pendingweapon = WP_THIRD;
  410.         }
  411.         else if(player->weaponowned[WP_SECOND]
  412.             && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_SECOND])
  413.         {
  414.             player->pendingweapon = WP_SECOND;
  415.         }
  416.         else if(player->weaponowned[WP_FOURTH]
  417.             && player->mana[MANA_1] >= WeaponManaUse[player->class][WP_FOURTH]
  418.             && player->mana[MANA_2] >= WeaponManaUse[player->class][WP_FOURTH])
  419.         {
  420.             player->pendingweapon = WP_FOURTH;
  421.         }
  422.         else
  423.         {
  424.             player->pendingweapon = WP_FIRST;
  425.         }
  426.     } while(player->pendingweapon == WP_NOCHANGE);
  427.     P_SetPsprite(player, ps_weapon,
  428.         WeaponInfo[player->readyweapon][player->class].downstate);
  429.     return(false);
  430. }
  431.  
  432. //---------------------------------------------------------------------------
  433. //
  434. // PROC P_FireWeapon
  435. //
  436. //---------------------------------------------------------------------------
  437.  
  438. void P_FireWeapon(player_t *player)
  439. {
  440.     statenum_t attackState;
  441.  
  442.     if(!P_CheckMana(player))
  443.     {
  444.         return;
  445.     }
  446.     P_SetMobjState(player->mo, PStateAttack[player->class]); // S_PLAY_ATK1);
  447.     if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
  448.     && player->mana[MANA_1] > 0)
  449.     { // Glowing axe
  450.         attackState = S_FAXEATK_G1;
  451.     }
  452.     else
  453.     {
  454.         attackState = player->refire ? 
  455.             WeaponInfo[player->readyweapon][player->class].holdatkstate
  456.             : WeaponInfo[player->readyweapon][player->class].atkstate;
  457.     }
  458.     P_SetPsprite(player, ps_weapon, attackState);
  459.     P_NoiseAlert(player->mo, player->mo);
  460. }
  461.  
  462. //---------------------------------------------------------------------------
  463. //
  464. // PROC P_DropWeapon
  465. //
  466. // The player died, so put the weapon away.
  467. //
  468. //---------------------------------------------------------------------------
  469.  
  470. void P_DropWeapon(player_t *player)
  471. {
  472.     P_SetPsprite(player, ps_weapon,
  473.         WeaponInfo[player->readyweapon][player->class].downstate);
  474. }
  475.  
  476. //---------------------------------------------------------------------------
  477. //
  478. // PROC A_WeaponReady
  479. //
  480. // The player can fire the weapon or change to another weapon at this time.
  481. //
  482. //---------------------------------------------------------------------------
  483.  
  484. void A_WeaponReady(player_t *player, pspdef_t *psp)
  485. {
  486.     int angle;
  487.  
  488.     // Change player from attack state
  489.     if(player->mo->state >= &states[PStateAttack[player->class]]
  490.         && player->mo->state <= &states[PStateAttackEnd[player->class]])
  491.     {
  492.         P_SetMobjState(player->mo, PStateNormal[player->class]);
  493.     }
  494.     // Put the weapon away if the player has a pending weapon or has
  495.     // died.
  496.     if(player->pendingweapon != WP_NOCHANGE || !player->health)
  497.     {
  498.         P_SetPsprite(player, ps_weapon,
  499.             WeaponInfo[player->readyweapon][player->class].downstate);
  500.         return;
  501.     }
  502.  
  503.     // Check for fire. 
  504.     if(player->cmd.buttons&BT_ATTACK)
  505.     {
  506.         player->attackdown = true;
  507.         P_FireWeapon(player);
  508.         return;
  509.     }
  510.     else
  511.     {
  512.         player->attackdown = false;
  513.     }
  514.  
  515.     if(!player->morphTics)
  516.     {
  517.         // Bob the weapon based on movement speed.
  518.         angle = (128*leveltime)&FINEMASK;
  519.         psp->sx = FRACUNIT+FixedMul(player->bob, finecosine[angle]);
  520.         angle &= FINEANGLES/2-1;
  521.         psp->sy = WEAPONTOP+FixedMul(player->bob, finesine[angle]);
  522.     }
  523. }
  524.  
  525. //---------------------------------------------------------------------------
  526. //
  527. // PROC A_ReFire
  528. //
  529. // The player can re fire the weapon without lowering it entirely.
  530. //
  531. //---------------------------------------------------------------------------
  532.  
  533. void A_ReFire(player_t *player, pspdef_t *psp)
  534. {
  535.     if((player->cmd.buttons&BT_ATTACK)
  536.         && player->pendingweapon == WP_NOCHANGE && player->health)
  537.     {
  538.         player->refire++;
  539.         P_FireWeapon(player);
  540.     }
  541.     else
  542.     {
  543.         player->refire = 0;
  544.         P_CheckMana(player);
  545.     }
  546. }
  547.  
  548. //---------------------------------------------------------------------------
  549. //
  550. // PROC A_Lower
  551. //
  552. //---------------------------------------------------------------------------
  553.  
  554. void A_Lower(player_t *player, pspdef_t *psp)
  555. {
  556.     if(player->morphTics)
  557.     {
  558.         psp->sy = WEAPONBOTTOM;
  559.     }
  560.     else
  561.     {
  562.         psp->sy += LOWERSPEED;
  563.     }
  564.     if(psp->sy < WEAPONBOTTOM)
  565.     { // Not lowered all the way yet
  566.         return;
  567.     }
  568.     if(player->playerstate == PST_DEAD)
  569.     { // Player is dead, so don't bring up a pending weapon
  570.         psp->sy = WEAPONBOTTOM;
  571.         return;
  572.     }
  573.     if(!player->health)
  574.     { // Player is dead, so keep the weapon off screen
  575.         P_SetPsprite(player,  ps_weapon, S_NULL);
  576.         return;
  577.     }
  578.     player->readyweapon = player->pendingweapon;
  579.     P_BringUpWeapon(player);
  580. }
  581.  
  582. //---------------------------------------------------------------------------
  583. //
  584. // PROC A_Raise
  585. //
  586. //---------------------------------------------------------------------------
  587.  
  588. void A_Raise(player_t *player, pspdef_t *psp)
  589. {
  590.     psp->sy -= RAISESPEED;
  591.     if(psp->sy > WEAPONTOP)
  592.     { // Not raised all the way yet
  593.         return;
  594.     }
  595.     psp->sy = WEAPONTOP;
  596.     if(player->class == PCLASS_FIGHTER && player->readyweapon == WP_SECOND
  597.     && player->mana[MANA_1])
  598.     {
  599.         P_SetPsprite(player, ps_weapon, S_FAXEREADY_G);
  600.     }
  601.     else
  602.     {    
  603.         P_SetPsprite(player, ps_weapon,
  604.             WeaponInfo[player->readyweapon][player->class].readystate);
  605.     }
  606. }
  607.  
  608. /*
  609. ===============
  610. =
  611. = P_BulletSlope
  612. =
  613. = Sets a slope so a near miss is at aproximately the height of the
  614. = intended target
  615. =
  616. ===============
  617. */
  618.  
  619. /*
  620. void P_BulletSlope (mobj_t *mo)
  621. {
  622.     angle_t        an;
  623.  
  624. //
  625. // see which target is to be aimed at
  626. //
  627.     an = mo->angle;
  628.     bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  629.     if (!linetarget)
  630.     {
  631.         an += 1<<26;
  632.         bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  633.         if (!linetarget)
  634.         {
  635.             an -= 2<<26;
  636.             bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
  637.         }
  638.         if (!linetarget)
  639.         {
  640.             an += 1<<26;
  641.             bulletslope = (mo->player->lookdir<<FRACBITS)/173;
  642.         }
  643.     }
  644. }
  645. */
  646.  
  647. //****************************************************************************
  648. //
  649. // WEAPON ATTACKS
  650. //
  651. //****************************************************************************
  652.  
  653. //============================================================================
  654. //
  655. //    AdjustPlayerAngle
  656. //
  657. //============================================================================
  658.  
  659. #define MAX_ANGLE_ADJUST (5*ANGLE_1)
  660.  
  661. void AdjustPlayerAngle(mobj_t *pmo)
  662. {
  663.     angle_t angle;
  664.     int difference;
  665.  
  666.     angle = R_PointToAngle2(pmo->x, pmo->y, linetarget->x, linetarget->y);
  667.     difference = (int)angle-(int)pmo->angle;
  668.     if(abs(difference) > MAX_ANGLE_ADJUST)
  669.     {
  670.         pmo->angle += difference > 0 ? MAX_ANGLE_ADJUST : -MAX_ANGLE_ADJUST;
  671.     }
  672.     else
  673.     {
  674.         pmo->angle = angle;
  675.     }
  676. }
  677.  
  678. //============================================================================
  679. //
  680. // A_SnoutAttack
  681. //
  682. //============================================================================
  683.  
  684. void A_SnoutAttack(player_t *player, pspdef_t *psp)
  685. {
  686.     angle_t angle;
  687.     int damage;
  688.     int slope;
  689.  
  690.     damage = 3+(P_Random()&3);
  691.     angle = player->mo->angle;
  692.     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
  693.     PuffType = MT_SNOUTPUFF;
  694.     PuffSpawned = NULL;
  695.     P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
  696.     S_StartSound(player->mo, SFX_PIG_ACTIVE1+(P_Random()&1));
  697.     if(linetarget)
  698.     {
  699.         AdjustPlayerAngle(player->mo);
  700. //        player->mo->angle = R_PointToAngle2(player->mo->x,
  701. //            player->mo->y, linetarget->x, linetarget->y);
  702.         if(PuffSpawned)
  703.         { // Bit something
  704.             S_StartSound(player->mo, SFX_PIG_ATTACK);
  705.         }
  706.     }
  707. }
  708.  
  709. //============================================================================
  710. //
  711. // A_FHammerAttack
  712. //
  713. //============================================================================
  714.  
  715. #define HAMMER_RANGE    (MELEERANGE+MELEERANGE/2)
  716.  
  717. void A_FHammerAttack(player_t *player, pspdef_t *psp)
  718. {
  719.     angle_t angle;
  720.     mobj_t *pmo=player->mo;
  721.     int damage;
  722.     fixed_t power;
  723.     int slope;
  724.     int i;
  725.  
  726.     damage = 60+(P_Random()&63);
  727.     power = 10*FRACUNIT;
  728.     PuffType = MT_HAMMERPUFF;
  729.     for(i = 0; i < 16; i++)
  730.     {
  731.         angle = pmo->angle+i*(ANG45/32);
  732.         slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
  733.         if(linetarget)
  734.         {
  735.             P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
  736.             AdjustPlayerAngle(pmo);
  737.             if (linetarget->flags&MF_COUNTKILL || linetarget->player)
  738.             {
  739.                 P_ThrustMobj(linetarget, angle, power);
  740.             }
  741.             pmo->special1 = false; // Don't throw a hammer
  742.             goto hammerdone;
  743.         }
  744.         angle = pmo->angle-i*(ANG45/32);
  745.         slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
  746.         if(linetarget)
  747.         {
  748.             P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
  749.             AdjustPlayerAngle(pmo);
  750.             if (linetarget->flags&MF_COUNTKILL || linetarget->player)
  751.             {
  752.                 P_ThrustMobj(linetarget, angle, power);
  753.             }
  754.             pmo->special1 = false; // Don't throw a hammer
  755.             goto hammerdone;
  756.         }
  757.     }
  758.     // didn't find any targets in meleerange, so set to throw out a hammer
  759.     PuffSpawned = NULL;
  760.     angle = pmo->angle;
  761.     slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE);
  762.     P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage);
  763.     if(PuffSpawned)
  764.     {
  765.         pmo->special1 = false;
  766.     }
  767.     else
  768.     {
  769.         pmo->special1 = true;
  770.     }
  771. hammerdone:
  772.     if(player->mana[MANA_2] < 
  773.         WeaponManaUse[player->class][player->readyweapon])
  774.     { // Don't spawn a hammer if the player doesn't have enough mana
  775.         pmo->special1 = false;
  776.     }
  777.     return;        
  778. }
  779.  
  780. //============================================================================
  781. //
  782. // A_FHammerThrow
  783. //
  784. //============================================================================
  785.  
  786. void A_FHammerThrow(player_t *player, pspdef_t *psp)
  787. {
  788.     mobj_t *mo;
  789.  
  790.     if(!player->mo->special1)
  791.     {
  792.         return;
  793.     }
  794.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  795.     mo = P_SpawnPlayerMissile(player->mo, MT_HAMMER_MISSILE); 
  796.     if(mo)
  797.     {
  798.         mo->special1 = 0;
  799.     }    
  800. }
  801.  
  802. //============================================================================
  803. //
  804. // A_FSwordAttack
  805. //
  806. //============================================================================
  807.  
  808. void A_FSwordAttack(player_t *player, pspdef_t *psp)
  809. {
  810.     mobj_t *pmo;
  811.  
  812.     player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
  813.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  814.     pmo = player->mo;
  815.     P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-10*FRACUNIT, MT_FSWORD_MISSILE, 
  816.         pmo->angle+ANG45/4);
  817.     P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z-5*FRACUNIT, MT_FSWORD_MISSILE, 
  818.         pmo->angle+ANG45/8);
  819.     P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z, MT_FSWORD_MISSILE, pmo->angle);
  820.     P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+5*FRACUNIT, MT_FSWORD_MISSILE, 
  821.         pmo->angle-ANG45/8);
  822.     P_SPMAngleXYZ(pmo, pmo->x, pmo->y, pmo->z+10*FRACUNIT, MT_FSWORD_MISSILE, 
  823.         pmo->angle-ANG45/4);
  824.     S_StartSound(pmo, SFX_FIGHTER_SWORD_FIRE);
  825. }
  826.  
  827. //============================================================================
  828. //
  829. // A_FSwordAttack2
  830. //
  831. //============================================================================
  832.  
  833. void A_FSwordAttack2(mobj_t *actor)
  834. {
  835.     angle_t angle = actor->angle;
  836.  
  837.     P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/4, 0);
  838.     P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle+ANG45/8, 0);
  839.     P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle,         0);
  840.     P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/8, 0);
  841.     P_SpawnMissileAngle(actor, MT_FSWORD_MISSILE,angle-ANG45/4, 0);
  842.     S_StartSound(actor, SFX_FIGHTER_SWORD_FIRE);
  843. }
  844.  
  845. //============================================================================
  846. //
  847. // A_FSwordFlames
  848. //
  849. //============================================================================
  850.  
  851. void A_FSwordFlames(mobj_t *actor)
  852. {
  853.     int i;
  854.  
  855.     for(i = 1+(P_Random()&3); i; i--)
  856.     {
  857.         P_SpawnMobj(actor->x+((P_Random()-128)<<12), actor->y
  858.             +((P_Random()-128)<<12), actor->z+((P_Random()-128)<<11),
  859.             MT_FSWORD_FLAME);
  860.     }
  861. }
  862.  
  863. //============================================================================
  864. //
  865. // A_MWandAttack
  866. //
  867. //============================================================================
  868.  
  869. void A_MWandAttack(player_t *player, pspdef_t *psp)
  870. {
  871.     mobj_t *mo;
  872.  
  873.     mo = P_SpawnPlayerMissile(player->mo, MT_MWAND_MISSILE);
  874.     if(mo)
  875.     {
  876.         mo->thinker.function = P_BlasterMobjThinker;
  877.     }
  878.     S_StartSound(player->mo, SFX_MAGE_WAND_FIRE);
  879. }
  880.  
  881. // ===== Mage Lightning Weapon =====
  882.  
  883. //============================================================================
  884. //
  885. // A_LightningReady
  886. //
  887. //============================================================================
  888.  
  889. void A_LightningReady(player_t *player, pspdef_t *psp)
  890. {
  891.     A_WeaponReady(player, psp);
  892.     if(P_Random() < 160)
  893.     {
  894.         S_StartSound(player->mo, SFX_MAGE_LIGHTNING_READY);
  895.     }
  896. }
  897.  
  898. //============================================================================
  899. //
  900. // A_LightningClip
  901. //
  902. //============================================================================
  903.  
  904. #define ZAGSPEED    FRACUNIT
  905.  
  906. void A_LightningClip(mobj_t *actor)
  907. {
  908.     mobj_t *cMo;
  909.     mobj_t *target;
  910.     int zigZag;
  911.  
  912.     if(actor->type == MT_LIGHTNING_FLOOR)
  913.     {
  914.         actor->z = actor->floorz;
  915.         target = (mobj_t *)((mobj_t *)actor->special2)->special1;
  916.     }
  917.     else if(actor->type == MT_LIGHTNING_CEILING)
  918.     {
  919.         actor->z = actor->ceilingz-actor->height;
  920.         target = (mobj_t *)actor->special1;
  921.     }
  922.     if(actor->type == MT_LIGHTNING_FLOOR)
  923.     { // floor lightning zig-zags, and forces the ceiling lightning to mimic
  924.         cMo = (mobj_t *)actor->special2;
  925.         zigZag = P_Random();
  926.         if((zigZag > 128 && actor->special1 < 2) || actor->special1 < -2)
  927.         {
  928.             P_ThrustMobj(actor, actor->angle+ANG90, ZAGSPEED);
  929.             if(cMo)
  930.             {
  931.                 P_ThrustMobj(cMo, actor->angle+ANG90, ZAGSPEED);
  932.             }
  933.             actor->special1++;
  934.         }
  935.         else
  936.         {
  937.             P_ThrustMobj(actor, actor->angle-ANG90, ZAGSPEED);
  938.             if(cMo)
  939.             {
  940.                 P_ThrustMobj(cMo, cMo->angle-ANG90, ZAGSPEED);
  941.             }
  942.             actor->special1--;
  943.         }
  944.     }
  945.     if(target)
  946.     {
  947.         if(target->health <= 0)
  948.         {
  949.             P_ExplodeMissile(actor);
  950.         }
  951.         else
  952.         {
  953.             actor->angle = R_PointToAngle2(actor->x, actor->y, target->x,
  954.                 target->y);
  955.             actor->momx = 0;
  956.             actor->momy = 0;
  957.             P_ThrustMobj(actor, actor->angle, actor->info->speed>>1);
  958.         }
  959.     }
  960. }
  961.  
  962. //============================================================================
  963. //
  964. // A_LightningZap
  965. //
  966. //============================================================================
  967.  
  968. void A_LightningZap(mobj_t *actor)
  969. {
  970.     mobj_t *mo;
  971.     fixed_t deltaZ;
  972.  
  973.     A_LightningClip(actor);
  974.  
  975.     actor->health -= 8;
  976.     if(actor->health <= 0)
  977.     {
  978.         P_SetMobjState(actor, actor->info->deathstate);
  979.         return;
  980.     }
  981.     if(actor->type == MT_LIGHTNING_FLOOR)
  982.     {
  983.         deltaZ = 10*FRACUNIT;
  984.     }
  985.     else
  986.     {
  987.         deltaZ = -10*FRACUNIT;
  988.     }
  989.     mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256), 
  990.         actor->y+((P_Random()-128)*actor->radius/256), 
  991.         actor->z+deltaZ, MT_LIGHTNING_ZAP);
  992.     if(mo)
  993.     {
  994.         mo->special2 = (int)actor;
  995.         mo->momx = actor->momx;
  996.         mo->momy = actor->momy;
  997.         mo->target = actor->target;
  998.         if(actor->type == MT_LIGHTNING_FLOOR)
  999.         {
  1000.             mo->momz = 20*FRACUNIT;
  1001.         }
  1002.         else 
  1003.         {
  1004.             mo->momz = -20*FRACUNIT;
  1005.         }
  1006.     }
  1007. /*
  1008.     mo = P_SpawnMobj(actor->x+((P_Random()-128)*actor->radius/256), 
  1009.         actor->y+((P_Random()-128)*actor->radius/256), 
  1010.         actor->z+deltaZ, MT_LIGHTNING_ZAP);
  1011.     if(mo)
  1012.     {
  1013.         mo->special2 = (int)actor;
  1014.         mo->momx = actor->momx;
  1015.         mo->momy = actor->momy;
  1016.         mo->target = actor->target;
  1017.         if(actor->type == MT_LIGHTNING_FLOOR)
  1018.         {
  1019.             mo->momz = 16*FRACUNIT;
  1020.         }
  1021.         else 
  1022.         {
  1023.             mo->momz = -16*FRACUNIT;
  1024.         }
  1025.     }
  1026. */
  1027.     if(actor->type == MT_LIGHTNING_FLOOR && P_Random() < 160)
  1028.     {
  1029.         S_StartSound(actor, SFX_MAGE_LIGHTNING_CONTINUOUS);
  1030.     }
  1031. }
  1032.  
  1033. //============================================================================
  1034. //
  1035. // A_MLightningAttack2
  1036. //
  1037. //============================================================================
  1038.  
  1039. void A_MLightningAttack2(mobj_t *actor)
  1040. {
  1041.     mobj_t *fmo, *cmo;
  1042.  
  1043.     fmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_FLOOR);
  1044.     cmo = P_SpawnPlayerMissile(actor, MT_LIGHTNING_CEILING);
  1045.     if(fmo)
  1046.     {
  1047.         fmo->special1 = 0;
  1048.         fmo->special2 = (int)cmo;
  1049.         A_LightningZap(fmo);    
  1050.     }
  1051.     if(cmo)
  1052.     {
  1053.         cmo->special1 = 0;    // mobj that it will track
  1054.         cmo->special2 = (int)fmo;
  1055.         A_LightningZap(cmo);    
  1056.     }
  1057.     S_StartSound(actor, SFX_MAGE_LIGHTNING_FIRE);
  1058. }
  1059.  
  1060. //============================================================================
  1061. //
  1062. // A_MLightningAttack
  1063. //
  1064. //============================================================================
  1065.  
  1066. void A_MLightningAttack(player_t *player, pspdef_t *psp)
  1067. {
  1068.     A_MLightningAttack2(player->mo);
  1069.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  1070. }
  1071.  
  1072. //============================================================================
  1073. //
  1074. // A_ZapMimic
  1075. //
  1076. //============================================================================
  1077.  
  1078. void A_ZapMimic(mobj_t *actor)
  1079. {
  1080.     mobj_t *mo;
  1081.  
  1082.     mo = (mobj_t *)actor->special2;
  1083.     if(mo)
  1084.     {
  1085.         if(mo->state >= &states[mo->info->deathstate]
  1086.             || mo->state == &states[S_FREETARGMOBJ])
  1087.         {
  1088.             P_ExplodeMissile(actor);
  1089.         }
  1090.         else
  1091.         {
  1092.             actor->momx = mo->momx;
  1093.             actor->momy = mo->momy;
  1094.         }
  1095.     }
  1096. }
  1097.  
  1098. //============================================================================
  1099. //
  1100. // A_LastZap
  1101. //
  1102. //============================================================================
  1103.  
  1104. void A_LastZap(mobj_t *actor)
  1105. {
  1106.     mobj_t *mo;
  1107.  
  1108.     mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_LIGHTNING_ZAP);
  1109.     if(mo)
  1110.     {
  1111.         P_SetMobjState(mo, S_LIGHTNING_ZAP_X1);
  1112.         mo->momz = 40*FRACUNIT;
  1113.     }
  1114. }
  1115.  
  1116. //============================================================================
  1117. //
  1118. // A_LightningRemove
  1119. //
  1120. //============================================================================
  1121.  
  1122. void A_LightningRemove(mobj_t *actor)
  1123. {
  1124.     mobj_t *mo;
  1125.  
  1126.     mo = (mobj_t *)actor->special2;
  1127.     if(mo)
  1128.     {
  1129.         mo->special2 = 0;
  1130.         P_ExplodeMissile(mo);
  1131.     }
  1132. }
  1133.  
  1134.  
  1135. //============================================================================
  1136. //
  1137. // MStaffSpawn
  1138. //
  1139. //============================================================================
  1140. void MStaffSpawn(mobj_t *pmo, angle_t angle)
  1141. {
  1142.     mobj_t *mo;
  1143.  
  1144.     mo = P_SPMAngle(pmo, MT_MSTAFF_FX2, angle);
  1145.     if (mo)
  1146.     {
  1147.         mo->target = pmo;
  1148.         mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
  1149.     }
  1150. }
  1151.  
  1152. //============================================================================
  1153. //
  1154. // A_MStaffAttack
  1155. //
  1156. //============================================================================
  1157.  
  1158. void A_MStaffAttack(player_t *player, pspdef_t *psp)
  1159. {
  1160.     angle_t angle;
  1161.     mobj_t *pmo;
  1162.  
  1163.     player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
  1164.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  1165.     pmo = player->mo;
  1166.     angle = pmo->angle;
  1167.     
  1168.     MStaffSpawn(pmo, angle);
  1169.     MStaffSpawn(pmo, angle-ANGLE_1*5);
  1170.     MStaffSpawn(pmo, angle+ANGLE_1*5);
  1171.     S_StartSound(player->mo, SFX_MAGE_STAFF_FIRE);
  1172.     if(player == &players[consoleplayer])
  1173.     {
  1174.         player->damagecount = 0;
  1175.         player->bonuscount = 0;
  1176.         I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
  1177.             PU_CACHE)+STARTSCOURGEPAL*768);
  1178.     }
  1179. }
  1180.  
  1181. //============================================================================
  1182. //
  1183. // A_MStaffPalette
  1184. //
  1185. //============================================================================
  1186.  
  1187. void A_MStaffPalette(player_t *player, pspdef_t *psp)
  1188. {
  1189.     int pal;
  1190.  
  1191.     if(player == &players[consoleplayer])
  1192.     {
  1193.         pal = STARTSCOURGEPAL+psp->state-(&states[S_MSTAFFATK_2]);
  1194.         if(pal == STARTSCOURGEPAL+3)
  1195.         { // reset back to original playpal
  1196.             pal = 0;
  1197.         }
  1198.         I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
  1199.             PU_CACHE)+pal*768);
  1200.     }
  1201. }
  1202.  
  1203. //============================================================================
  1204. //
  1205. // A_MStaffWeave
  1206. //
  1207. //============================================================================
  1208.  
  1209. void A_MStaffWeave(mobj_t *actor)
  1210. {
  1211.     fixed_t newX, newY;
  1212.     int weaveXY, weaveZ;
  1213.     int angle;
  1214.  
  1215.     weaveXY = actor->special2>>16;
  1216.     weaveZ = actor->special2&0xFFFF;
  1217.     angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
  1218.     newX = actor->x-FixedMul(finecosine[angle], 
  1219.         FloatBobOffsets[weaveXY]<<2);
  1220.     newY = actor->y-FixedMul(finesine[angle],
  1221.         FloatBobOffsets[weaveXY]<<2);
  1222.     weaveXY = (weaveXY+6)&63;
  1223.     newX += FixedMul(finecosine[angle], 
  1224.         FloatBobOffsets[weaveXY]<<2);
  1225.     newY += FixedMul(finesine[angle], 
  1226.         FloatBobOffsets[weaveXY]<<2);
  1227.     P_TryMove(actor, newX, newY);
  1228.     actor->z -= FloatBobOffsets[weaveZ]<<1;
  1229.     weaveZ = (weaveZ+3)&63;
  1230.     actor->z += FloatBobOffsets[weaveZ]<<1;
  1231.     if(actor->z <= actor->floorz)
  1232.     {
  1233.         actor->z = actor->floorz+FRACUNIT;
  1234.     }
  1235.     actor->special2 = weaveZ+(weaveXY<<16);
  1236. }
  1237.  
  1238.  
  1239. //============================================================================
  1240. //
  1241. // A_MStaffTrack
  1242. //
  1243. //============================================================================
  1244.  
  1245. void A_MStaffTrack(mobj_t *actor)
  1246. {
  1247.     if ((actor->special1 == 0) && (P_Random()<50))
  1248.     {
  1249.         actor->special1 = (int)P_RoughMonsterSearch(actor, 10);
  1250.     }
  1251.     P_SeekerMissile(actor, ANGLE_1*2, ANGLE_1*10);
  1252. }
  1253.  
  1254.  
  1255. //============================================================================
  1256. //
  1257. // MStaffSpawn2 - for use by mage class boss
  1258. //
  1259. //============================================================================
  1260.  
  1261. void MStaffSpawn2(mobj_t *actor, angle_t angle)
  1262. {
  1263.     mobj_t *mo;
  1264.  
  1265.     mo = P_SpawnMissileAngle(actor, MT_MSTAFF_FX2, angle, 0);
  1266.     if (mo)
  1267.     {
  1268.         mo->target = actor;
  1269.         mo->special1 = (int)P_RoughMonsterSearch(mo, 10);
  1270.     }
  1271. }
  1272.  
  1273. //============================================================================
  1274. //
  1275. // A_MStaffAttack2 - for use by mage class boss
  1276. //
  1277. //============================================================================
  1278.  
  1279. void A_MStaffAttack2(mobj_t *actor)
  1280. {
  1281.     angle_t angle;
  1282.     angle = actor->angle;
  1283.     MStaffSpawn2(actor, angle);
  1284.     MStaffSpawn2(actor, angle-ANGLE_1*5);
  1285.     MStaffSpawn2(actor, angle+ANGLE_1*5);
  1286.     S_StartSound(actor, SFX_MAGE_STAFF_FIRE);
  1287. }
  1288.  
  1289. //============================================================================
  1290. //
  1291. // A_FPunchAttack
  1292. //
  1293. //============================================================================
  1294.  
  1295. void A_FPunchAttack(player_t *player, pspdef_t *psp)
  1296. {
  1297.     angle_t angle;
  1298.     int damage;
  1299.     int slope;
  1300.     mobj_t *pmo = player->mo;
  1301.     fixed_t power;
  1302.     int i;
  1303.  
  1304.     damage = 40+(P_Random()&15);
  1305.     power = 2*FRACUNIT;
  1306.     PuffType = MT_PUNCHPUFF;
  1307.     for(i = 0; i < 16; i++)
  1308.     {
  1309.         angle = pmo->angle+i*(ANG45/16);
  1310.         slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
  1311.         if(linetarget)
  1312.         {
  1313.             player->mo->special1++;
  1314.             if(pmo->special1 == 3)
  1315.             {
  1316.                 damage <<= 1;
  1317.                 power = 6*FRACUNIT;
  1318.                 PuffType = MT_HAMMERPUFF;
  1319.             }
  1320.             P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
  1321.             if (linetarget->flags&MF_COUNTKILL || linetarget->player)
  1322.             {
  1323.                 P_ThrustMobj(linetarget, angle, power);
  1324.             }
  1325.             AdjustPlayerAngle(pmo);
  1326.             goto punchdone;
  1327.         }
  1328.         angle = pmo->angle-i*(ANG45/16);
  1329.         slope = P_AimLineAttack(pmo, angle, 2*MELEERANGE);
  1330.         if(linetarget)
  1331.         {
  1332.             pmo->special1++;
  1333.             if(pmo->special1 == 3)
  1334.             {
  1335.                 damage <<= 1;
  1336.                 power = 6*FRACUNIT;
  1337.                 PuffType = MT_HAMMERPUFF;
  1338.             }
  1339.             P_LineAttack(pmo, angle, 2*MELEERANGE, slope, damage);
  1340.             if (linetarget->flags&MF_COUNTKILL || linetarget->player)
  1341.             {
  1342.                 P_ThrustMobj(linetarget, angle, power);
  1343.             }
  1344.             AdjustPlayerAngle(pmo);
  1345.             goto punchdone;
  1346.         }
  1347.     }
  1348.     // didn't find any creatures, so try to strike any walls
  1349.     pmo->special1 = 0;
  1350.  
  1351.     angle = pmo->angle;
  1352.     slope = P_AimLineAttack(pmo, angle, MELEERANGE);
  1353.     P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
  1354.  
  1355. punchdone:
  1356.     if(pmo->special1 == 3)
  1357.     {
  1358.         pmo->special1 = 0;
  1359.         P_SetPsprite(player, ps_weapon, S_PUNCHATK2_1);
  1360.         S_StartSound(pmo, SFX_FIGHTER_GRUNT);
  1361.     }
  1362.     return;        
  1363. }
  1364.  
  1365. //============================================================================
  1366. //
  1367. // A_FAxeAttack
  1368. //
  1369. //============================================================================
  1370.  
  1371. #define AXERANGE    2.25*MELEERANGE
  1372.  
  1373. void A_FAxeAttack(player_t *player, pspdef_t *psp)
  1374. {
  1375.     angle_t angle;
  1376.     mobj_t *pmo=player->mo;
  1377.     fixed_t power;
  1378.     int damage;
  1379.     int slope;
  1380.     int i;
  1381.     int useMana;
  1382.  
  1383.     damage = 40+(P_Random()&15)+(P_Random()&7);
  1384.     power = 0;
  1385.     if(player->mana[MANA_1] > 0)
  1386.     {
  1387.         damage <<= 1;
  1388.         power = 6*FRACUNIT;
  1389.         PuffType = MT_AXEPUFF_GLOW;
  1390.         useMana = 1;
  1391.     }
  1392.     else
  1393.     {
  1394.         PuffType = MT_AXEPUFF;
  1395.         useMana = 0;
  1396.     }
  1397.     for(i = 0; i < 16; i++)
  1398.     {
  1399.         angle = pmo->angle+i*(ANG45/16);
  1400.         slope = P_AimLineAttack(pmo, angle, AXERANGE);
  1401.         if(linetarget)
  1402.         {
  1403.             P_LineAttack(pmo, angle, AXERANGE, slope, damage);
  1404.             if (linetarget->flags&MF_COUNTKILL || linetarget->player)
  1405.             {
  1406.                 P_ThrustMobj(linetarget, angle, power);
  1407.             }
  1408.             AdjustPlayerAngle(pmo);
  1409.             useMana++; 
  1410.             goto axedone;
  1411.         }
  1412.         angle = pmo->angle-i*(ANG45/16);
  1413.         slope = P_AimLineAttack(pmo, angle, AXERANGE);
  1414.         if(linetarget)
  1415.         {
  1416.             P_LineAttack(pmo, angle, AXERANGE, slope, damage);
  1417.             if (linetarget->flags&MF_COUNTKILL)
  1418.             {
  1419.                 P_ThrustMobj(linetarget, angle, power);
  1420.             }
  1421.             AdjustPlayerAngle(pmo);
  1422.             useMana++; 
  1423.             goto axedone;
  1424.         }
  1425.     }
  1426.     // didn't find any creatures, so try to strike any walls
  1427.     pmo->special1 = 0;
  1428.  
  1429.     angle = pmo->angle;
  1430.     slope = P_AimLineAttack(pmo, angle, MELEERANGE);
  1431.     P_LineAttack(pmo, angle, MELEERANGE, slope, damage);
  1432.  
  1433. axedone:
  1434.     if(useMana == 2)
  1435.     {
  1436.         player->mana[MANA_1] -= 
  1437.             WeaponManaUse[player->class][player->readyweapon];
  1438.         if(player->mana[MANA_1] <= 0)
  1439.         {
  1440.             P_SetPsprite(player, ps_weapon, S_FAXEATK_5);
  1441.         }
  1442.     }
  1443.     return;        
  1444. }
  1445.  
  1446. //===========================================================================
  1447. //
  1448. // A_CMaceAttack
  1449. //
  1450. //===========================================================================
  1451.  
  1452. void A_CMaceAttack(player_t *player, pspdef_t *psp)
  1453. {
  1454.     angle_t angle;
  1455.     int damage;
  1456.     int slope;
  1457.     int i;
  1458.  
  1459.     damage = 25+(P_Random()&15);
  1460.     PuffType = MT_HAMMERPUFF;
  1461.     for(i = 0; i < 16; i++)
  1462.     {
  1463.         angle = player->mo->angle+i*(ANG45/16);
  1464.         slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
  1465.         if(linetarget)
  1466.         {
  1467.             P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, 
  1468.                 damage);
  1469.             AdjustPlayerAngle(player->mo);
  1470. //            player->mo->angle = R_PointToAngle2(player->mo->x,
  1471. //                player->mo->y, linetarget->x, linetarget->y);
  1472.             goto macedone;
  1473.         }
  1474.         angle = player->mo->angle-i*(ANG45/16);
  1475.         slope = P_AimLineAttack(player->mo, angle, 2*MELEERANGE);
  1476.         if(linetarget)
  1477.         {
  1478.             P_LineAttack(player->mo, angle, 2*MELEERANGE, slope, 
  1479.                 damage);
  1480.             AdjustPlayerAngle(player->mo);
  1481. //            player->mo->angle = R_PointToAngle2(player->mo->x,
  1482. //                player->mo->y, linetarget->x, linetarget->y);
  1483.             goto macedone;
  1484.         }
  1485.     }
  1486.     // didn't find any creatures, so try to strike any walls
  1487.     player->mo->special1 = 0;
  1488.  
  1489.     angle = player->mo->angle;
  1490.     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
  1491.     P_LineAttack(player->mo, angle, MELEERANGE, slope, 
  1492.         damage);
  1493. macedone:
  1494.     return;        
  1495. }
  1496.  
  1497. //============================================================================
  1498. //
  1499. // A_CStaffCheck
  1500. //
  1501. //============================================================================
  1502.  
  1503. void A_CStaffCheck(player_t *player, pspdef_t *psp)
  1504. {
  1505.     mobj_t *pmo;
  1506.     int damage;
  1507.     int newLife;
  1508.     angle_t angle;
  1509.     int slope;
  1510.     int i;
  1511.  
  1512.     pmo = player->mo;
  1513.     damage = 20+(P_Random()&15);
  1514.     PuffType = MT_CSTAFFPUFF;
  1515.     for(i = 0; i < 3; i++)
  1516.     {
  1517.         angle = pmo->angle+i*(ANG45/16);
  1518.         slope = P_AimLineAttack(pmo, angle, 1.5*MELEERANGE);
  1519.         if(linetarget)
  1520.         {
  1521.             P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
  1522.             pmo->angle = R_PointToAngle2(pmo->x, pmo->y, 
  1523.                 linetarget->x, linetarget->y);
  1524.             if((linetarget->player || linetarget->flags&MF_COUNTKILL)
  1525.                 && (!(linetarget->flags2&(MF2_DORMANT+MF2_INVULNERABLE))))
  1526.             {
  1527.                 newLife = player->health+(damage>>3);
  1528.                 newLife = newLife > 100 ? 100 : newLife;
  1529.                 pmo->health = player->health = newLife;
  1530.                 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
  1531.             }
  1532.             player->mana[MANA_1] -= 
  1533.                 WeaponManaUse[player->class][player->readyweapon];
  1534.             break;
  1535.         }
  1536.         angle = pmo->angle-i*(ANG45/16);
  1537.         slope = P_AimLineAttack(player->mo, angle, 1.5*MELEERANGE);
  1538.         if(linetarget)
  1539.         {
  1540.             P_LineAttack(pmo, angle, 1.5*MELEERANGE, slope, damage);
  1541.             pmo->angle = R_PointToAngle2(pmo->x, pmo->y, 
  1542.                 linetarget->x, linetarget->y);
  1543.             if(linetarget->player || linetarget->flags&MF_COUNTKILL)
  1544.             {
  1545.                 newLife = player->health+(damage>>4);
  1546.                 newLife = newLife > 100 ? 100 : newLife;
  1547.                 pmo->health = player->health = newLife;
  1548.                 P_SetPsprite(player, ps_weapon, S_CSTAFFATK2_1);
  1549.             }
  1550.             player->mana[MANA_1] -= 
  1551.                 WeaponManaUse[player->class][player->readyweapon];
  1552.             break;
  1553.         }
  1554.     }
  1555. }
  1556.  
  1557. //============================================================================
  1558. //
  1559. // A_CStaffAttack
  1560. //
  1561. //============================================================================
  1562.  
  1563. void A_CStaffAttack(player_t *player, pspdef_t *psp)
  1564. {
  1565.     mobj_t *mo;
  1566.     mobj_t *pmo;
  1567.  
  1568.     player->mana[MANA_1] -=    WeaponManaUse[player->class][player->readyweapon];
  1569.     pmo = player->mo;
  1570.     mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle-(ANG45/15));
  1571.     if(mo)
  1572.     {
  1573.         mo->special2 = 32;
  1574.     }
  1575.     mo = P_SPMAngle(pmo, MT_CSTAFF_MISSILE, pmo->angle+(ANG45/15));
  1576.     if(mo)
  1577.     {
  1578.         mo->special2 = 0;
  1579.     }
  1580.     S_StartSound(player->mo, SFX_CLERIC_CSTAFF_FIRE);
  1581. }
  1582.  
  1583. //============================================================================
  1584. //
  1585. // A_CStaffMissileSlither
  1586. //
  1587. //============================================================================
  1588.  
  1589. void A_CStaffMissileSlither(mobj_t *actor)
  1590. {
  1591.     fixed_t newX, newY;
  1592.     int weaveXY;
  1593.     int angle;
  1594.  
  1595.     weaveXY = actor->special2;
  1596.     angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
  1597.     newX = actor->x-FixedMul(finecosine[angle], 
  1598.         FloatBobOffsets[weaveXY]);
  1599.     newY = actor->y-FixedMul(finesine[angle],
  1600.         FloatBobOffsets[weaveXY]);
  1601.     weaveXY = (weaveXY+3)&63;
  1602.     newX += FixedMul(finecosine[angle], 
  1603.         FloatBobOffsets[weaveXY]);
  1604.     newY += FixedMul(finesine[angle], 
  1605.         FloatBobOffsets[weaveXY]);
  1606.     P_TryMove(actor, newX, newY);
  1607.     actor->special2 = weaveXY;    
  1608. }
  1609.  
  1610. //============================================================================
  1611. //
  1612. // A_CStaffInitBlink
  1613. //
  1614. //============================================================================
  1615.  
  1616. void A_CStaffInitBlink(player_t *player, pspdef_t *psp)
  1617. {
  1618.     player->mo->special1 = (P_Random()>>1)+20;
  1619. }
  1620.  
  1621. //============================================================================
  1622. //
  1623. // A_CStaffCheckBlink
  1624. //
  1625. //============================================================================
  1626.  
  1627. void A_CStaffCheckBlink(player_t *player, pspdef_t *psp)
  1628. {
  1629.     if(!--player->mo->special1)
  1630.     {
  1631.         P_SetPsprite(player, ps_weapon, S_CSTAFFBLINK1);
  1632.         player->mo->special1 = (P_Random()+50)>>2;
  1633.     }
  1634. }
  1635.  
  1636. //============================================================================
  1637. //
  1638. // A_CFlameAttack
  1639. //
  1640. //============================================================================
  1641.  
  1642. #define FLAMESPEED    (0.45*FRACUNIT)
  1643. #define CFLAMERANGE    (12*64*FRACUNIT)
  1644.  
  1645. void A_CFlameAttack(player_t *player, pspdef_t *psp)
  1646. {
  1647.     mobj_t *mo;
  1648.  
  1649.     mo = P_SpawnPlayerMissile(player->mo, MT_CFLAME_MISSILE);
  1650.     if(mo)
  1651.     {
  1652.         mo->thinker.function = P_BlasterMobjThinker;
  1653.         mo->special1 = 2;
  1654.     }
  1655.  
  1656.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  1657.     S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
  1658. }
  1659.  
  1660. //============================================================================
  1661. //
  1662. // A_CFlamePuff
  1663. //
  1664. //============================================================================
  1665.  
  1666. void A_CFlamePuff(mobj_t *actor)
  1667. {
  1668.     A_UnHideThing(actor);
  1669.     actor->momx = 0;
  1670.     actor->momy = 0;
  1671.     actor->momz = 0;
  1672.     S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
  1673. }
  1674.  
  1675. //============================================================================
  1676. //
  1677. // A_CFlameMissile
  1678. //
  1679. //============================================================================
  1680.  
  1681. void A_CFlameMissile(mobj_t *actor)
  1682. {
  1683.     int i;
  1684.     int an, an90;
  1685.     fixed_t dist;
  1686.     mobj_t *mo;
  1687.     
  1688.     A_UnHideThing(actor);
  1689.     S_StartSound(actor, SFX_CLERIC_FLAME_EXPLODE);
  1690.     if(BlockingMobj && BlockingMobj->flags&MF_SHOOTABLE)
  1691.     { // Hit something, so spawn the flame circle around the thing
  1692.         dist = BlockingMobj->radius+18*FRACUNIT;
  1693.         for(i = 0; i < 4; i++)
  1694.         {
  1695.             an = (i*ANG45)>>ANGLETOFINESHIFT;
  1696.             an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
  1697.             mo = P_SpawnMobj(BlockingMobj->x+FixedMul(dist, finecosine[an]),
  1698.                 BlockingMobj->y+FixedMul(dist, finesine[an]), 
  1699.                 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
  1700.             if(mo)
  1701.             {
  1702.                 mo->angle = an<<ANGLETOFINESHIFT;
  1703.                 mo->target = actor->target;
  1704.                 mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
  1705.                 mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
  1706.                 mo->tics -= P_Random()&3;
  1707.             }
  1708.             mo = P_SpawnMobj(BlockingMobj->x-FixedMul(dist, finecosine[an]),
  1709.                 BlockingMobj->y-FixedMul(dist, finesine[an]), 
  1710.                 BlockingMobj->z+5*FRACUNIT, MT_CIRCLEFLAME);
  1711.             if(mo)
  1712.             {
  1713.                 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
  1714.                 mo->target = actor->target;
  1715.                 mo->momx = mo->special1 = FixedMul(-FLAMESPEED, 
  1716.                     finecosine[an]);
  1717.                 mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
  1718.                 mo->tics -= P_Random()&3;
  1719.             }
  1720.         }
  1721.         P_SetMobjState(actor, S_FLAMEPUFF2_1);
  1722.     }
  1723. }
  1724.  
  1725. /*
  1726. void A_CFlameAttack(player_t *player, pspdef_t *psp)
  1727. {
  1728.     mobj_t *pmo;
  1729.     angle_t angle;
  1730.     int damage;
  1731.     int i;
  1732.     int an, an90;
  1733.     fixed_t dist;
  1734.     mobj_t *mo;
  1735.  
  1736.     pmo = player->mo;
  1737.     P_BulletSlope(pmo);
  1738.     damage = 25+HITDICE(3);
  1739.     angle = pmo->angle;
  1740.     if(player->refire)
  1741.     {
  1742.         angle += (P_Random()-P_Random())<<17;
  1743.     }
  1744.     P_AimLineAttack(pmo, angle, CFLAMERANGE); // Correctly set linetarget
  1745.     if(!linetarget)
  1746.     {
  1747.         angle += ANGLE_1*2;
  1748.         P_AimLineAttack(pmo, angle, CFLAMERANGE);
  1749.         if(!linetarget)
  1750.         {
  1751.             angle -= ANGLE_1*4;
  1752.             P_AimLineAttack(pmo, angle, CFLAMERANGE);
  1753.             if(!linetarget)
  1754.             {
  1755.                 angle += ANGLE_1*2;
  1756.             }
  1757.         }        
  1758.     }
  1759.     if(linetarget)
  1760.     {
  1761.         PuffType = MT_FLAMEPUFF2;
  1762.     }
  1763.     else
  1764.     {
  1765.         PuffType = MT_FLAMEPUFF;
  1766.     }
  1767.     P_LineAttack(pmo, angle, CFLAMERANGE, bulletslope, damage);
  1768.     if(linetarget)
  1769.     { // Hit something, so spawn the flame circle around the thing
  1770.         dist = linetarget->radius+18*FRACUNIT;
  1771.         for(i = 0; i < 4; i++)
  1772.         {
  1773.             an = (i*ANG45)>>ANGLETOFINESHIFT;
  1774.             an90 = (i*ANG45+ANG90)>>ANGLETOFINESHIFT;
  1775.             mo = P_SpawnMobj(linetarget->x+FixedMul(dist, finecosine[an]),
  1776.                 linetarget->y+FixedMul(dist, finesine[an]), 
  1777.                 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
  1778.             if(mo)
  1779.             {
  1780.                 mo->angle = an<<ANGLETOFINESHIFT;
  1781.                 mo->target = pmo;
  1782.                 mo->momx = mo->special1 = FixedMul(FLAMESPEED, finecosine[an]);
  1783.                 mo->momy = mo->special2 = FixedMul(FLAMESPEED, finesine[an]);
  1784.                 mo->tics -= P_Random()&3;
  1785.             }
  1786.             mo = P_SpawnMobj(linetarget->x-FixedMul(dist, finecosine[an]),
  1787.                 linetarget->y-FixedMul(dist, finesine[an]), 
  1788.                 linetarget->z+5*FRACUNIT, MT_CIRCLEFLAME);
  1789.             if(mo)
  1790.             {
  1791.                 mo->angle = ANG180+(an<<ANGLETOFINESHIFT);
  1792.                 mo->target = pmo;
  1793.                 mo->momx = mo->special1 = FixedMul(-FLAMESPEED, 
  1794.                     finecosine[an]);
  1795.                 mo->momy = mo->special2 = FixedMul(-FLAMESPEED, finesine[an]);
  1796.                 mo->tics -= P_Random()&3;
  1797.             }
  1798.         }
  1799.     }
  1800. // Create a line of flames from the player to the flame puff
  1801.     CFlameCreateFlames(player->mo);
  1802.  
  1803.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  1804.     S_StartSound(player->mo, SFX_CLERIC_FLAME_FIRE);
  1805. }
  1806. */
  1807.  
  1808. //============================================================================
  1809. //
  1810. // A_CFlameRotate
  1811. //
  1812. //============================================================================
  1813.  
  1814. #define FLAMEROTSPEED    2*FRACUNIT
  1815.  
  1816. void A_CFlameRotate(mobj_t *actor)
  1817. {
  1818.     int an;
  1819.  
  1820.     an = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
  1821.     actor->momx = actor->special1+FixedMul(FLAMEROTSPEED, finecosine[an]);
  1822.     actor->momy = actor->special2+FixedMul(FLAMEROTSPEED, finesine[an]);
  1823.     actor->angle += ANG90/15;
  1824. }
  1825.  
  1826.  
  1827. //============================================================================
  1828. //
  1829. // A_CHolyAttack3
  1830. //
  1831. //     Spawns the spirits
  1832. //============================================================================
  1833.  
  1834. void A_CHolyAttack3(mobj_t *actor)
  1835. {
  1836.     P_SpawnMissile(actor, actor->target, MT_HOLY_MISSILE);
  1837.     S_StartSound(actor, SFX_CHOLY_FIRE);
  1838. }
  1839.  
  1840.  
  1841. //============================================================================
  1842. //
  1843. // A_CHolyAttack2 
  1844. //
  1845. //     Spawns the spirits
  1846. //============================================================================
  1847.  
  1848. void A_CHolyAttack2(mobj_t *actor)
  1849. {
  1850.     int j;
  1851.     int i;
  1852.     mobj_t *mo;
  1853.     mobj_t *tail, *next;
  1854.  
  1855.     for(j = 0; j < 4; j++)
  1856.     {
  1857.         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_FX);
  1858.         if(!mo)
  1859.         {
  1860.             continue;
  1861.         }
  1862.         switch(j)
  1863.         { // float bob index
  1864.             case 0:
  1865.                 mo->special2 = P_Random()&7; // upper-left
  1866.                 break;
  1867.             case 1:
  1868.                 mo->special2 = 32+(P_Random()&7); // upper-right
  1869.                 break;
  1870.             case 2:
  1871.                 mo->special2 = (32+(P_Random()&7))<<16; // lower-left
  1872.                 break;
  1873.             case 3:
  1874.                 mo->special2 = ((32+(P_Random()&7))<<16)+32+(P_Random()&7);
  1875.                 break;
  1876.         }
  1877.         mo->z = actor->z;
  1878.         mo->angle = actor->angle+(ANGLE_45+ANGLE_45/2)-ANGLE_45*j;
  1879.         P_ThrustMobj(mo, mo->angle, mo->info->speed);
  1880.         mo->target = actor->target;
  1881.         mo->args[0] = 10; // initial turn value
  1882.         mo->args[1] = 0; // initial look angle
  1883.         if(deathmatch)
  1884.         { // Ghosts last slightly less longer in DeathMatch
  1885.             mo->health = 85;
  1886.         }
  1887.         if(linetarget)
  1888.         {
  1889.             mo->special1 = (int)linetarget;
  1890.             mo->flags |= MF_NOCLIP|MF_SKULLFLY;
  1891.             mo->flags &= ~MF_MISSILE;
  1892.         }
  1893.         tail = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
  1894.         tail->special2 = (int)mo; // parent
  1895.         for(i = 1; i < 3; i++)
  1896.         {
  1897.             next = P_SpawnMobj(mo->x, mo->y, mo->z, MT_HOLY_TAIL);
  1898.             P_SetMobjState(next, next->info->spawnstate+1);
  1899.             tail->special1 = (int)next;
  1900.             tail = next;
  1901.         }
  1902.         tail->special1 = 0; // last tail bit
  1903.     }
  1904. }
  1905.  
  1906. //============================================================================
  1907. //
  1908. // A_CHolyAttack
  1909. //
  1910. //============================================================================
  1911.  
  1912. void A_CHolyAttack(player_t *player, pspdef_t *psp)
  1913. {
  1914.     mobj_t *mo;
  1915.  
  1916.     player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
  1917.     player->mana[MANA_2] -= WeaponManaUse[player->class][player->readyweapon];
  1918.     mo = P_SpawnPlayerMissile(player->mo, MT_HOLY_MISSILE);
  1919.     if(player == &players[consoleplayer])
  1920.     {
  1921.         player->damagecount = 0;
  1922.         player->bonuscount = 0;
  1923.         I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
  1924.             PU_CACHE)+STARTHOLYPAL*768);
  1925.     }
  1926.     S_StartSound(player->mo, SFX_CHOLY_FIRE);
  1927. }
  1928.  
  1929. //============================================================================
  1930. //
  1931. // A_CHolyPalette
  1932. //
  1933. //============================================================================
  1934.  
  1935. void A_CHolyPalette(player_t *player, pspdef_t *psp)
  1936. {
  1937.     int pal;
  1938.  
  1939.     if(player == &players[consoleplayer])
  1940.     {
  1941.         pal = STARTHOLYPAL+psp->state-(&states[S_CHOLYATK_6]);
  1942.         if(pal == STARTHOLYPAL+3)
  1943.         { // reset back to original playpal
  1944.             pal = 0;
  1945.         }
  1946.         I_SetPalette((byte *)W_CacheLumpNum(W_GetNumForName("playpal"),
  1947.             PU_CACHE)+pal*768);
  1948.     }
  1949. }
  1950.  
  1951. //============================================================================
  1952. //
  1953. // CHolyFindTarget
  1954. //
  1955. //============================================================================
  1956.  
  1957. static void CHolyFindTarget(mobj_t *actor)
  1958. {
  1959.     mobj_t *target;
  1960.  
  1961.     if(target = P_RoughMonsterSearch(actor, 6))
  1962.     {
  1963.         actor->special1 = (int)target;
  1964.         actor->flags |= MF_NOCLIP|MF_SKULLFLY;
  1965.         actor->flags &= ~MF_MISSILE;
  1966.     }
  1967. }
  1968.  
  1969. //============================================================================
  1970. //
  1971. // CHolySeekerMissile
  1972. //
  1973. //      Similar to P_SeekerMissile, but seeks to a random Z on the target
  1974. //============================================================================
  1975.  
  1976. static void CHolySeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
  1977. {
  1978.     int dir;
  1979.     int dist;
  1980.     angle_t delta;
  1981.     angle_t angle;
  1982.     mobj_t *target;
  1983.     fixed_t newZ;
  1984.     fixed_t deltaZ;
  1985.  
  1986.     target = (mobj_t *)actor->special1;
  1987.     if(target == NULL)
  1988.     {
  1989.         return;
  1990.     }
  1991.     if(!(target->flags&MF_SHOOTABLE) 
  1992.     || (!(target->flags&MF_COUNTKILL) && !target->player))
  1993.     { // Target died/target isn't a player or creature
  1994.         actor->special1 = 0;
  1995.         actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
  1996.         actor->flags |= MF_MISSILE;
  1997.         CHolyFindTarget(actor);
  1998.         return;
  1999.     }
  2000.     dir = P_FaceMobj(actor, target, &delta);
  2001.     if(delta > thresh)
  2002.     {
  2003.         delta >>= 1;
  2004.         if(delta > turnMax)
  2005.         {
  2006.             delta = turnMax;
  2007.         }
  2008.     }
  2009.     if(dir)
  2010.     { // Turn clockwise
  2011.         actor->angle += delta;
  2012.     }
  2013.     else
  2014.     { // Turn counter clockwise
  2015.         actor->angle -= delta;
  2016.     }
  2017.     angle = actor->angle>>ANGLETOFINESHIFT;
  2018.     actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
  2019.     actor->momy = FixedMul(actor->info->speed, finesine[angle]);
  2020.     if(!(leveltime&15) 
  2021.         || actor->z > target->z+(target->height)
  2022.         || actor->z+actor->height < target->z)
  2023.     {
  2024.         newZ = target->z+((P_Random()*target->height)>>8);
  2025.         deltaZ = newZ-actor->z;
  2026.         if(abs(deltaZ) > 15*FRACUNIT)
  2027.         {
  2028.             if(deltaZ > 0)
  2029.             {
  2030.                 deltaZ = 15*FRACUNIT;
  2031.             }
  2032.             else
  2033.             {
  2034.                 deltaZ = -15*FRACUNIT;
  2035.             }
  2036.         }
  2037.         dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
  2038.         dist = dist/actor->info->speed;
  2039.         if(dist < 1)
  2040.         {
  2041.             dist = 1;
  2042.         }
  2043.         actor->momz = deltaZ/dist;
  2044.     }
  2045.     return;
  2046. }
  2047.  
  2048. //============================================================================
  2049. //
  2050. // A_CHolyWeave
  2051. //
  2052. //============================================================================
  2053.  
  2054. static void CHolyWeave(mobj_t *actor)
  2055. {
  2056.     fixed_t newX, newY;
  2057.     int weaveXY, weaveZ;
  2058.     int angle;
  2059.  
  2060.     weaveXY = actor->special2>>16;
  2061.     weaveZ = actor->special2&0xFFFF;
  2062.     angle = (actor->angle+ANG90)>>ANGLETOFINESHIFT;
  2063.     newX = actor->x-FixedMul(finecosine[angle], 
  2064.         FloatBobOffsets[weaveXY]<<2);
  2065.     newY = actor->y-FixedMul(finesine[angle],
  2066.         FloatBobOffsets[weaveXY]<<2);
  2067.     weaveXY = (weaveXY+(P_Random()%5))&63;
  2068.     newX += FixedMul(finecosine[angle], 
  2069.         FloatBobOffsets[weaveXY]<<2);
  2070.     newY += FixedMul(finesine[angle], 
  2071.         FloatBobOffsets[weaveXY]<<2);
  2072.     P_TryMove(actor, newX, newY);
  2073.     actor->z -= FloatBobOffsets[weaveZ]<<1;
  2074.     weaveZ = (weaveZ+(P_Random()%5))&63;
  2075.     actor->z += FloatBobOffsets[weaveZ]<<1;    
  2076.     actor->special2 = weaveZ+(weaveXY<<16);
  2077. }
  2078.  
  2079. //============================================================================
  2080. //
  2081. // A_CHolySeek
  2082. //
  2083. //============================================================================
  2084.  
  2085. void A_CHolySeek(mobj_t *actor)
  2086. {
  2087.     actor->health--;
  2088.     if(actor->health <= 0)
  2089.     {
  2090.         actor->momx >>= 2;
  2091.         actor->momy >>= 2;
  2092.         actor->momz = 0;
  2093.         P_SetMobjState(actor, actor->info->deathstate);
  2094.         actor->tics -= P_Random()&3;
  2095.         return;
  2096.     }
  2097.     if(actor->special1)
  2098.     {
  2099.         CHolySeekerMissile(actor, actor->args[0]*ANGLE_1,
  2100.             actor->args[0]*ANGLE_1*2);
  2101.         if(!((leveltime+7)&15))
  2102.         {
  2103.             actor->args[0] = 5+(P_Random()/20);
  2104.         }
  2105.     }
  2106.     CHolyWeave(actor);
  2107. }
  2108.  
  2109. //============================================================================
  2110. //
  2111. // CHolyTailFollow
  2112. //
  2113. //============================================================================
  2114.  
  2115. static void CHolyTailFollow(mobj_t *actor, fixed_t dist)
  2116. {
  2117.     mobj_t *child;
  2118.     int an;
  2119.     fixed_t oldDistance, newDistance;
  2120.  
  2121.     child = (mobj_t *)actor->special1;
  2122.     if(child)
  2123.     {
  2124.         an = R_PointToAngle2(actor->x, actor->y, child->x, 
  2125.             child->y)>>ANGLETOFINESHIFT;
  2126.         oldDistance = P_AproxDistance(child->x-actor->x, child->y-actor->y);
  2127.         if(P_TryMove(child, actor->x+FixedMul(dist, finecosine[an]), 
  2128.             actor->y+FixedMul(dist, finesine[an])))
  2129.         {
  2130.             newDistance = P_AproxDistance(child->x-actor->x, 
  2131.                 child->y-actor->y)-FRACUNIT;
  2132.             if(oldDistance < FRACUNIT)
  2133.             {
  2134.                 if(child->z < actor->z)
  2135.                 {
  2136.                     child->z = actor->z-dist;
  2137.                 }
  2138.                 else
  2139.                 {
  2140.                     child->z = actor->z+dist;
  2141.                 }
  2142.             }
  2143.             else
  2144.             {
  2145.                 child->z = actor->z+FixedMul(FixedDiv(newDistance, 
  2146.                     oldDistance), child->z-actor->z);
  2147.             }
  2148.         }
  2149.         CHolyTailFollow(child, dist-FRACUNIT);
  2150.     }
  2151. }
  2152.  
  2153. //============================================================================
  2154. //
  2155. // CHolyTailRemove
  2156. //
  2157. //============================================================================
  2158.  
  2159. static void CHolyTailRemove(mobj_t *actor)
  2160. {
  2161.     mobj_t *child;
  2162.  
  2163.     child = (mobj_t *)actor->special1;
  2164.     if(child)
  2165.     {
  2166.         CHolyTailRemove(child);
  2167.     }
  2168.     P_RemoveMobj(actor);
  2169. }
  2170.  
  2171. //============================================================================
  2172. //
  2173. // A_CHolyTail
  2174. //
  2175. //============================================================================
  2176.  
  2177. void A_CHolyTail(mobj_t *actor)
  2178. {
  2179.     mobj_t *parent;
  2180.  
  2181.     parent = (mobj_t *)actor->special2;
  2182.  
  2183.     if(parent)
  2184.     {
  2185.         if(parent->state >= &states[parent->info->deathstate])
  2186.         { // Ghost removed, so remove all tail parts
  2187.             CHolyTailRemove(actor);
  2188.             return;
  2189.         }
  2190.         else if(P_TryMove(actor, parent->x-FixedMul(14*FRACUNIT,
  2191.             finecosine[parent->angle>>ANGLETOFINESHIFT]),
  2192.             parent->y-FixedMul(14*FRACUNIT, 
  2193.             finesine[parent->angle>>ANGLETOFINESHIFT])))
  2194.         {
  2195.             actor->z = parent->z-5*FRACUNIT;
  2196.         }
  2197.         CHolyTailFollow(actor, 10*FRACUNIT);
  2198.     }
  2199. }
  2200. //============================================================================
  2201. //
  2202. // A_CHolyCheckScream
  2203. //
  2204. //============================================================================
  2205.  
  2206. void A_CHolyCheckScream(mobj_t *actor)
  2207. {
  2208.     A_CHolySeek(actor);
  2209.     if(P_Random() < 20)
  2210.     {
  2211.         S_StartSound(actor, SFX_SPIRIT_ACTIVE);
  2212.     }
  2213.     if(!actor->special1)
  2214.     {
  2215.         CHolyFindTarget(actor);
  2216.     }
  2217. }
  2218.  
  2219. //============================================================================
  2220. //
  2221. // A_CHolySpawnPuff
  2222. //
  2223. //============================================================================
  2224.  
  2225. void A_CHolySpawnPuff(mobj_t *actor)
  2226. {
  2227.     P_SpawnMobj(actor->x, actor->y, actor->z, MT_HOLY_MISSILE_PUFF);
  2228. }
  2229.  
  2230. //----------------------------------------------------------------------------
  2231. //
  2232. // PROC A_FireConePL1
  2233. //
  2234. //----------------------------------------------------------------------------
  2235.  
  2236. #define SHARDSPAWN_LEFT        1
  2237. #define SHARDSPAWN_RIGHT    2
  2238. #define SHARDSPAWN_UP        4
  2239. #define SHARDSPAWN_DOWN        8
  2240.  
  2241. void A_FireConePL1(player_t *player, pspdef_t *psp)
  2242. {
  2243.     angle_t angle;
  2244.     int damage;
  2245.     int slope;
  2246.     int i;
  2247.     mobj_t *pmo,*mo;
  2248.     int conedone=false;
  2249.  
  2250.     pmo = player->mo;
  2251.     player->mana[MANA_1] -= WeaponManaUse[player->class][player->readyweapon];
  2252.     S_StartSound(pmo, SFX_MAGE_SHARDS_FIRE);
  2253.  
  2254.     damage = 90+(P_Random()&15);
  2255.     for(i = 0; i < 16; i++)
  2256.     {
  2257.         angle = pmo->angle+i*(ANG45/16);
  2258.         slope = P_AimLineAttack(pmo, angle, MELEERANGE);
  2259.         if(linetarget)
  2260.         {
  2261.             pmo->flags2 |= MF2_ICEDAMAGE;
  2262.             P_DamageMobj(linetarget, pmo, pmo, damage);
  2263.             pmo->flags2 &= ~MF2_ICEDAMAGE;
  2264.             conedone = true;
  2265.             break;
  2266.         }
  2267.     }
  2268.  
  2269.     // didn't find any creatures, so fire projectiles
  2270.     if (!conedone)
  2271.     {
  2272.         mo = P_SpawnPlayerMissile(pmo, MT_SHARDFX1);
  2273.         if (mo)
  2274.         {
  2275.             mo->special1 = SHARDSPAWN_LEFT|SHARDSPAWN_DOWN|SHARDSPAWN_UP
  2276.                 |SHARDSPAWN_RIGHT;
  2277.             mo->special2 = 3; // Set sperm count (levels of reproductivity)
  2278.             mo->target = pmo;
  2279.             mo->args[0] = 3;        // Mark Initial shard as super damage
  2280.         }
  2281.     }
  2282. }
  2283.  
  2284. void A_ShedShard(mobj_t *actor)
  2285. {
  2286.     mobj_t *mo;
  2287.     int spawndir = actor->special1;
  2288.     int spermcount = actor->special2;
  2289.  
  2290.     if (spermcount <= 0) return;                // No sperm left
  2291.     actor->special2 = 0;
  2292.     spermcount--;
  2293.  
  2294.     // every so many calls, spawn a new missile in it's set directions
  2295.     if (spawndir & SHARDSPAWN_LEFT)
  2296.     {
  2297.         mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle+(ANG45/9),
  2298.                                              0, (20+2*spermcount)<<FRACBITS);
  2299.         if (mo)
  2300.         {
  2301.             mo->special1 = SHARDSPAWN_LEFT;
  2302.             mo->special2 = spermcount;
  2303.             mo->momz = actor->momz;
  2304.             mo->target = actor->target;
  2305.             mo->args[0] = (spermcount==3)?2:0;
  2306.         }
  2307.     }
  2308.     if (spawndir & SHARDSPAWN_RIGHT)
  2309.     {
  2310.         mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle-(ANG45/9),
  2311.                                              0, (20+2*spermcount)<<FRACBITS);
  2312.         if (mo)
  2313.         {
  2314.             mo->special1 = SHARDSPAWN_RIGHT;
  2315.             mo->special2 = spermcount;
  2316.             mo->momz = actor->momz;
  2317.             mo->target = actor->target;
  2318.             mo->args[0] = (spermcount==3)?2:0;
  2319.         }
  2320.     }
  2321.     if (spawndir & SHARDSPAWN_UP)
  2322.     {
  2323.         mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 
  2324.                                              0, (15+2*spermcount)<<FRACBITS);
  2325.         if (mo)
  2326.         {
  2327.             mo->momz = actor->momz;
  2328.             mo->z += 8*FRACUNIT;
  2329.             if (spermcount & 1)            // Every other reproduction
  2330.                 mo->special1 = SHARDSPAWN_UP | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
  2331.             else
  2332.                 mo->special1 = SHARDSPAWN_UP;
  2333.             mo->special2 = spermcount;
  2334.             mo->target = actor->target;
  2335.             mo->args[0] = (spermcount==3)?2:0;
  2336.         }
  2337.     }
  2338.     if (spawndir & SHARDSPAWN_DOWN)
  2339.     {
  2340.         mo=P_SpawnMissileAngleSpeed(actor, MT_SHARDFX1, actor->angle, 
  2341.                                              0, (15+2*spermcount)<<FRACBITS);
  2342.         if (mo)
  2343.         {
  2344.             mo->momz = actor->momz;
  2345.             mo->z -= 4*FRACUNIT;
  2346.             if (spermcount & 1)            // Every other reproduction
  2347.                 mo->special1 = SHARDSPAWN_DOWN | SHARDSPAWN_LEFT | SHARDSPAWN_RIGHT;
  2348.             else
  2349.                 mo->special1 = SHARDSPAWN_DOWN;
  2350.             mo->special2 = spermcount;
  2351.             mo->target = actor->target;
  2352.             mo->args[0] = (spermcount==3)?2:0;
  2353.         }
  2354.     }
  2355. }
  2356.  
  2357. //----------------------------------------------------------------------------
  2358. //
  2359. // PROC A_HideInCeiling
  2360. //
  2361. //----------------------------------------------------------------------------
  2362.  
  2363. /*
  2364. void A_HideInCeiling(mobj_t *actor)
  2365. {
  2366.     actor->z = actor->ceilingz+4*FRACUNIT;
  2367. }
  2368. */
  2369.  
  2370. //----------------------------------------------------------------------------
  2371. //
  2372. // PROC A_FloatPuff
  2373. //
  2374. //----------------------------------------------------------------------------
  2375.  
  2376. /*
  2377. void A_FloatPuff(mobj_t *puff)
  2378. {
  2379.     puff->momz += 1.8*FRACUNIT;
  2380. }
  2381. */
  2382.  
  2383. void A_Light0(player_t *player, pspdef_t *psp)
  2384. {
  2385.     player->extralight = 0;
  2386. }
  2387.  
  2388. /*
  2389. void A_Light1(player_t *player, pspdef_t *psp)
  2390. {
  2391.     player->extralight = 1;
  2392. }
  2393. */
  2394.  
  2395. /*
  2396. void A_Light2(player_t *player, pspdef_t *psp)
  2397. {
  2398.     player->extralight = 2;
  2399. }
  2400. */
  2401.  
  2402. //------------------------------------------------------------------------
  2403. //
  2404. // PROC P_SetupPsprites
  2405. //
  2406. // Called at start of level for each player
  2407. //
  2408. //------------------------------------------------------------------------
  2409.  
  2410. void P_SetupPsprites(player_t *player)
  2411. {
  2412.     int i;
  2413.  
  2414.     // Remove all psprites
  2415.     for(i = 0; i < NUMPSPRITES; i++)
  2416.     {
  2417.         player->psprites[i].state = NULL;
  2418.     }
  2419.     // Spawn the ready weapon
  2420.     player->pendingweapon = player->readyweapon;
  2421.     P_BringUpWeapon(player);
  2422. }
  2423.  
  2424. //------------------------------------------------------------------------
  2425. //
  2426. // PROC P_MovePsprites
  2427. //
  2428. // Called every tic by player thinking routine
  2429. //
  2430. //------------------------------------------------------------------------
  2431.  
  2432. void P_MovePsprites(player_t *player)
  2433. {
  2434.     int i;
  2435.     pspdef_t *psp;
  2436.     state_t *state;
  2437.  
  2438.     psp = &player->psprites[0];
  2439.     for(i = 0; i < NUMPSPRITES; i++, psp++)
  2440.     {
  2441.         if((state = psp->state) != 0) // a null state means not active
  2442.         {
  2443.             // drop tic count and possibly change state
  2444.             if(psp->tics != -1)    // a -1 tic count never changes
  2445.             {
  2446.                 psp->tics--;
  2447.                 if(!psp->tics)
  2448.                 {
  2449.                     P_SetPsprite(player, i, psp->state->nextstate);
  2450.                 }
  2451.             }
  2452.         }
  2453.     }
  2454.     player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
  2455.     player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
  2456. }
  2457.